package com.hex.es.aop;

import com.hex.es.annotation.EnableEsProxy;
import com.hex.es.annotation.EsHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * @ClassName EsScannerRegistrar
 * @Description EsScannerRegistrar
 * @Author hex
 * @Date 2020/12/18 18:21
 * @Version 1.0
 */
@Slf4j
public class EsScannerRegistrar implements ImportBeanDefinitionRegistrar, BeanClassLoaderAware, ResourceLoaderAware, EnvironmentAware {

    private ResourceLoader resourceLoader;

    private Environment environment;

    private ClassLoader classLoader;

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        ClassPathScanningCandidateComponentProvider scanner = getScanner();
        scanner.setResourceLoader(this.resourceLoader);
        //指定只关注标注了@EsHandler注解的接口
        scanner.addIncludeFilter(new AnnotationTypeFilter(EsHandler.class));
        Set<String> basePackages = getBasePackages(importingClassMetadata);
        if(CollectionUtils.isNotEmpty(basePackages)) {
            for (String basePackage : basePackages) {
                //扫描出BeanDefinition
                Set<BeanDefinition> beanDefinitionSet = scanner.findCandidateComponents(basePackage);
                if(CollectionUtils.isNotEmpty(beanDefinitionSet)) {
                    for (BeanDefinition beanDefinition : beanDefinitionSet) {
                        if (beanDefinition instanceof AnnotatedBeanDefinition) {
                            registerSingleHandlerSpiBeanDefinition((AnnotatedBeanDefinition) beanDefinition, registry);
                        }
                    }
                }
            }
        }
    }

    /**
     * 注入spring容器
     * @param beanDefinition
     * @param registry
     */
    private void registerSingleHandlerSpiBeanDefinition(AnnotatedBeanDefinition beanDefinition, BeanDefinitionRegistry registry) {
        AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
        Assert.isTrue(annotationMetadata.isInterface(),"@EsHandler can only be specified on an interface");
        String beanClassName = beanDefinition.getBeanClassName();
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(EsFactoryBean.class);
        try {
            Class<?> clazz = Class.forName(beanClassName);
            builder.addPropertyValue("classInterface",clazz);
            registry.registerBeanDefinition(StringUtils.uncapitalize(clazz.getSimpleName()), builder.getBeanDefinition());
        } catch (Exception e) {
            throw new RuntimeException("register es beanDefinition fail, beanClassName : "+beanClassName,e);
        }
    }

    /**
     * 获取需要扫描的路径
     * @param importingClassMetadata
     * @return
     */
    private Set<String> getBasePackages(AnnotationMetadata importingClassMetadata) {
        Set<String> basePackages = new HashSet<>();
        Map<String, Object> attrs = importingClassMetadata.getAnnotationAttributes(EnableEsProxy.class.getName());
        if(null != attrs) {
            for (String pkg : (String[]) attrs.get("value")) {
                if (StringUtils.hasText(pkg)) {
                    basePackages.add(pkg);
                }
            }
        }
        return basePackages;
    }


    /**
     * 构造Class扫描器，设置了只扫描顶级接口，不扫描内部类
     * @return
     */
    protected ClassPathScanningCandidateComponentProvider getScanner() {
        return new ClassPathScanningCandidateComponentProvider(false, this.environment) {
            @Override
            protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
                boolean isCandidate = false;
                if (beanDefinition.getMetadata().isIndependent() && beanDefinition.getMetadata().isInterface()) {
                    isCandidate = true;
                }
                return isCandidate;
            }
        };
    }
}
